home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / dev / basic / ace24dist.lha / ace24.lha / utils / ab2ascii-1.3 / main.c < prev    next >
C/C++ Source or Header  |  1996-09-11  |  10KB  |  417 lines

  1. /*
  2.     AmigaBASIC -> ASCII  -- generate ASCII source from AmigaBASIC binaries
  3.  
  4.     Original version by Stefan Reisner, sr@ph-cip.uni-koeln.de
  5.     Revised & bug-fixes by Tobias Ferber, ukjg@dkauni2.bitnet
  6. */
  7.  
  8. /*
  9.  * (c)Copyright 1994 by Tobias Ferber.
  10.  *
  11.  * This file is part of AmigaBASIC->ASCII.
  12.  *
  13.  * AmigaBASIC->ASCII is free software; you can redistribute it and/or
  14.  * modify it under the terms of the GNU General Public License as
  15.  * published by the Free Software Foundation; either version 1 of the
  16.  * License, or (at your option) any later version.
  17.  *
  18.  * AmigaBASIC->ASCII is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with AmigaBASIC->ASCII; see the file COPYING.  If not, write to
  25.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  */
  27.  
  28. #include "abasic.h"
  29.  
  30. /* include the version tag */
  31. #include "ab2ascii.c"
  32. #include "version.h"
  33.  
  34. /* globals */
  35.  
  36. /* the symbol table */
  37. symbol_t *sym_tab= NIL(symbol_t *);
  38. int numsyms;
  39.  
  40. /* the list of code lines */
  41. codeline_t *code_buffer= NIL(codeline_t *);
  42. long current_line, numlines;
  43.  
  44. char *whoami; /* argv[0] */
  45. char *infile;
  46. int debuglevel= 0;
  47.  
  48. /* input, output and error stream */
  49. FILE *fin, *fout, *ferr;
  50.  
  51. static void display_version_information(void)
  52. {
  53.   static char license[]=
  54.     "AmigaBASIC->ASCII is free software; you can redistribute it and/or\n"
  55.     "modify it under the terms of the GNU General Public License as\n"
  56.     "published by the Free Software Foundation; either version 1 of the\n"
  57.     "License, or (at your option) any later version.\n"
  58.     "\n"
  59.     "AmigaBASIC->ASCII is distributed in the hope that it will be useful,\n"
  60.     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  61.     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
  62.     "GNU General Public License for more details.\n"
  63.     "\n"
  64.     "You should have received a copy of the GNU General Public License\n"
  65.     "along with AmigaBASIC->ASCII; see the file COPYING.  If not, write to the\n"
  66.     "Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
  67.     ;
  68.  
  69.   puts("AmigaBASIC->ASCII Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
  70.        "(c)Copyright 1994 by Tobias Ferber, ukjg@dkauni2.bitnet\n");
  71.  
  72.   puts(license);
  73. }
  74.  
  75.  
  76. void warn(const char *fmt, ...)
  77. {
  78.   va_list argp;
  79.   va_start(argp,fmt);
  80.   fprintf(ferr,"%s: ",whoami);
  81.  
  82.   if(infile)
  83.     fprintf(ferr,"%s: ",infile);
  84.  
  85.   vfprintf(ferr,(char *)fmt,argp);
  86.   fprintf(ferr,"\n");
  87.   fflush(ferr);
  88.   va_end(argp);
  89. }
  90.  
  91.  
  92. int dothehardpart( void )
  93. {
  94.   int len, c, n=0;
  95.   int faux_pas= 0;
  96.   long codesize= 0;
  97.  
  98.   /* initialize globals */
  99.  
  100.   numsyms= numlines= 0;
  101.  
  102.   /* begin scanning the input stream */
  103.  
  104.   c= fgetc(fin);
  105.  
  106.   if(c != 0xf5)
  107.   {
  108.     warn("Hmmm... this doesn't look like an AmigaBASIC binary.\n"
  109.          "My output will probably look a bit funny.  Proceed, for a laugh.");
  110.   }
  111.  
  112.   if( feof(fin) || ferror(fin) )
  113.   { warn("unexpected end of input -- no code, no symbols");
  114.     return 1;
  115.   }
  116.  
  117.   /* read the code segment */
  118.  
  119.   do {
  120.  
  121.     /* Stefan Reisner thought that AmigaBASIC encodes the length of a line
  122.      * in a 2 byte word prefix.  This is not the whole truth...
  123.      * I've experienced that the first byte holds a flag (e.g. 0x80 indicates
  124.      * a line number) and only the second byte encodes the length.
  125.      */
  126.  
  127.     c= fgetc(fin); /* flags */
  128.  
  129.     if( len= fgetc(fin) )
  130.     {
  131.       codesize += len;
  132.       len-= 2;
  133.  
  134.       if( !feof(fin) && !ferror(fin) )
  135.         n= read_line(fin,len,c);
  136.     }
  137.  
  138.   } while( len && n == len && !ferror(fin) && !feof(fin) );
  139.  
  140.   if( len )
  141.   {
  142.     if( n != len || ferror(fin) )
  143.     {
  144.       warn("I'm confused; after having read the code segment, I still seem\n"
  145.            "to want to go on.  In fact I just wanted to read another %d bytes\n"
  146.            "when a serious problem interrupted me.  I'll try to forget about this.",len);
  147.     }
  148.  
  149.     if( feof(fin) )
  150.     {
  151.       warn("Uh, oh.  I suspect there was a null missing at the end of the code segment,\n"
  152.            "causing me to read past where I should stop.\n"
  153.            "I'll forget about the symbols now.  Proceed, with fingers crossed.");
  154.     }
  155.   }
  156.   else if( feof(fin) || ferror(fin) ) /* and len <= 0 */
  157.     warn("This seems to be a funny program.  The input ended without any symbol definitions.\n");
  158.  
  159.   /* read the symbols */
  160.  
  161.   if( !ferror(fin) && !feof(fin) )
  162.   {
  163.     int ok= 1;
  164.  
  165. #ifdef DEBUG
  166.     if(debuglevel >= 1)
  167.       fprintf(stderr,"skipping a '\\x%02x' character\n",fgetc(fin));
  168.     else
  169. #endif
  170.       (void)fgetc(fin);  /* skip null byte */
  171.  
  172.     if( (codesize & 1) == 0 )
  173.     {
  174. #ifdef DEBUG
  175.       if(debuglevel >= 1)
  176.         fprintf(stderr,"skipping another '\\x%02x' character\n",fgetc(fin));
  177.       else
  178. #endif
  179.       (void)fgetc(fin);
  180.     }
  181.  
  182.     if( feof(fin) || ferror(fin) )
  183.     {
  184.       warn("I was just about to read the symbols when I reached the end of file.\n"
  185.            "Maybe we have a BASIC program without symbols?  We'll see...");
  186.     }
  187.  
  188.     else do {
  189.       len= fgetc(fin);
  190.  
  191.       if( !feof(fin) )
  192.         ok= read_sym(fin, len, numsyms++);
  193.  
  194.     } while( ok && !feof(fin) && !ferror(fin) );
  195.  
  196.     if( !ok )
  197.     {
  198.       warn("After having read %ld %s I couldn't get another %d bytes.\n"
  199.            "Maybe there is not enough free store?  I'll better stop reading symbols!",
  200.            numsyms-1, (numsyms-1 == 1) ? "symbol": "symbols");
  201.     }
  202.   }
  203.  
  204. #ifdef DEBUG
  205.     if(debuglevel >= 1)
  206.       fprintf(stderr,"expanding %ld lines of code w/ %d symbols\n",numlines,numsyms);
  207. #endif
  208.  
  209.   expand_code();
  210.  
  211.   /* we _must_ call these to become re-entrant */
  212.  
  213.   free_symbols();
  214.   free_code();
  215.  
  216.   return faux_pas;
  217. }
  218.  
  219.  
  220. /*
  221.    Generate a filename from a format string fmt and the replacement string s for
  222.    the first `%s' in fmt and open this file for write.
  223.    Normally the FILE pointer will be returned, 0 indicates a serious problem.
  224.    This function prints warning messages via warn().
  225. */
  226.  
  227. FILE *fmtopen( char *fmt, char *s )
  228. {
  229.   FILE *fp= (FILE *)0L;
  230.  
  231.   char *fname= (char *)malloc( strlen(s) + strlen(fmt) );
  232.  
  233.   if(fname)
  234.   {
  235.     sprintf(fname,fmt,s);
  236.     fp= fopen(fname,"w");
  237.  
  238.     if(!fp)
  239.       warn("can't write to `%s'",fname);
  240.   }
  241.   else warn("out of memory... aaaiiiiiieeeeeeeee!");
  242.  
  243.   if(fname)
  244.     free(fname);
  245.  
  246.   return fp;
  247. }
  248.  
  249.  
  250. int main( int argc, char **argv )
  251. {
  252.   int badopt= 0;
  253.   int numfiles= 0;
  254.   char *outfmt;
  255.  
  256. #ifdef _DCC /* Dice */
  257.   expand_args(argc,argv, &argc,&argv);
  258. #endif /* _DCC */
  259.  
  260.   infile= outfmt= (char *)0L;
  261.   whoami= *argv;
  262.  
  263.   fin= stdin;
  264.   fout= stdout;
  265.   ferr= stderr;
  266.  
  267.   while(--argc>0 && !badopt)
  268.   {
  269.     char *arg= *++argv;
  270.  
  271.     if(*arg=='-')
  272.     {
  273.       if(arg[1]=='-')
  274.         arg= convert_args(*argv);
  275.  
  276.       switch(*++arg)
  277.       {
  278.  
  279. /*-d*/  case 'd':
  280. #ifdef DEBUG
  281.           debuglevel= 1;
  282. #else
  283.           echo("not compiled w/ a symbol DEBUG defined.  No debugging information available -- Sorry.");
  284. #endif
  285.           break;
  286.  
  287. /*-E*/  case 'E':
  288.           if(arg[1]) ++arg;
  289.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  290.  
  291.           if(arg && *arg)
  292.           {
  293.             if(ferr != stderr)
  294.             {
  295.               warn("warning: option `%s' has already been seen!",*argv);
  296.               fclose(ferr);
  297.             }
  298.  
  299.             ferr= fopen(arg,"w");
  300.  
  301.             if(!ferr)
  302.             {
  303.               warn("can't direct error output to `%s' -- will use stderr",arg);
  304.               ferr= stderr;
  305.             }
  306.           }
  307.           else
  308.           { warn("missing filename after `%s' option",*argv);
  309.             ++badopt;
  310.           }
  311.           break;
  312.  
  313. /*-?*/  case '?':
  314. /*-h*/  case 'h':
  315.           fprintf(stderr,
  316.             "usage: %s [options] [-o|>] [outfile] [<] [infiles..]\n\n",whoami);
  317.  
  318.           display_args();
  319.           badopt= 1; /* hack: means exit. */
  320.           break;
  321.  
  322. /*-o*/  case 'o':
  323.           if(arg[1]) ++arg;
  324.           else arg= (--argc > 0) ? *(++argv) : (char *)0L;
  325.  
  326.           if(arg && *arg)
  327.           {
  328.             if(outfmt)
  329.               warn("option `%s' has already been seen!",*argv);
  330.             outfmt= arg;
  331.           }
  332.           else
  333.           {
  334.             warn("missing output filename after `%s' option",*argv);
  335.             ++badopt;
  336.           }
  337.           break;
  338.  
  339. /*-s*/  case 's':
  340.           warn("silent option `%s' is not yet implemented -- sorry.",*argv);
  341.           break;
  342.  
  343. /*-v*/  case 'v':
  344.           display_version_information();
  345.           badopt= 1; /* hack: means exit. */
  346.           break;
  347.  
  348. /*??*/  default:
  349.           warn("unrecognized option `%s'",*argv);
  350.           ++badopt;
  351.           break;
  352.       }
  353.     }
  354.     else
  355.     {
  356.       if(arg && *arg)
  357.       {
  358.         if( chain_fname(arg) )
  359.         {
  360.           warn("out of memory... aaaiiiiiieeeeeeeee!");
  361.           ++badopt;
  362.         }
  363.         else ++numfiles;
  364.       }
  365.       else
  366.       {
  367.         warn("command line error: can't parse `%s'",arg);
  368.         ++badopt;
  369.       }
  370.     }
  371.   }
  372.  
  373.  
  374.   if(numfiles)
  375.   {
  376.     while( !badopt && (infile= unchain_fname()) )
  377.     {
  378.       if( fin= fopen(infile,"rb") )
  379.       {
  380.         if( fout= outfmt ? fmtopen(outfmt, infile) : stdout )
  381.         {
  382.           badopt= dothehardpart();
  383.  
  384.           if(fout != stdout)
  385.             fclose(fout);
  386.         }
  387.         else ++badopt; /* fmtopen() has already warned */
  388.         fclose(fin);
  389.       }
  390.       else
  391.       {
  392.         warn("can't access your input file `%s'",infile);
  393.         ++badopt;
  394.       }
  395.     }
  396.     purge_flist();
  397.   }
  398.  
  399.   else if( !badopt )
  400.   {
  401.     if( fout= outfmt ? fmtopen(outfmt, "stdin") : stdout )
  402.     {
  403.       badopt= dothehardpart();
  404.  
  405.       if(fout != stdout)
  406.          fclose(fout);
  407.     }
  408.     else ++badopt; /* fmtopen() has already warned */
  409.   }
  410.  
  411.   if(fin  && fin  != stdin)    fclose(fin);
  412.   if(fout && fout != stdout)   fclose(fout);
  413.   if(ferr && ferr != stderr)   fclose(ferr);
  414.  
  415.   exit( badopt ? 1:0 );
  416. }
  417.